/**
 * @file A_shell.c
 * @author MooN
 * @brief 
 * @version 0.0.1
 * @date 2022-08-24
 * 
 * @copyright (c) 2022 Moon
 * 
 */

#include "shell.h"
#include "A_shell.h"

/* freertos include*/
#if     SHELL_USING_LOCK == 1
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#endif

#if ASHELL_ASYNCHRONOUS == 1
#include "public_queue.h"
static queue_t shell_queue;
static uint8_t shell_buf[ASHELL_QUEUE_LEN];
#endif

Shell shell;
char shellBuffer[512];

#if SHELL_USING_LOCK == 1
static SemaphoreHandle_t shellMutex;
#endif

#if ASHELL_ASYNCHRONOUS == 1
#if ASHELL_USE_RTOS == 1
static void AShellTaskProcess(void *pvParameters);
#endif
#endif
/**
 * @brief 用户shell读
 * 
 * @param data 数据
 * @param len 数据长度
 * 
 * @return short 实际读取到
 */
short userShellRead(char *data, unsigned short len)
{
#if ASHELL_ASYNCHRONOUS == 1
    uint16_t shell_len = 0;

    shell_len = DataQueueGetLen(&shell_queue);
    if (shell_len == 0)
        return 0;
    if (len < shell_len)
    {
        shell_len = len;
    }
    DataQueueRead(&shell_queue, (uint8_t *)data, shell_len);
    return shell_len;
#else    
    return 0;
#endif
}

#if SHELL_USING_LOCK == 1
/**
 * @brief 用户shell上锁
 * 
 * @param shell shell
 * 
 * @return int 0
 */
int userShellLock(Shell *shell)
{
    if (0 != ASHELL_IRQ_STA())
    {
        xSemaphoreTake(shellMutex, portMAX_DELAY);
    }
    else
    {
        xSemaphoreTakeFromISR(shellMutex, NULL);
    }
    return 0;
}

/**
 * @brief 用户shell解锁
 * 
 * @param shell shell
 * 
 * @return int 0
 */
int userShellUnlock(Shell *shell)
{
    if (0 != ASHELL_IRQ_STA())
    {
        xSemaphoreGive(shellMutex);
    }
    else
    {
        xSemaphoreGiveFromISR(shellMutex, NULL);
    }
    return 0;
}
#endif

/**
 * @brief 用户shell初始化
 * 
 */
void AShellInit(signed short (*write)(char *, unsigned short), int (*flush)(void))
{
#if ASHELL_ASYNCHRONOUS == 1
    DataQueueInit(&shell_queue, shell_buf, ASHELL_QUEUE_LEN);
#endif
    shell.write = write;
    shell.read = userShellRead;
    shell.flush = flush;

#if SHELL_USING_LOCK == 1
    shellMutex = xSemaphoreCreateMutex();
    shell.lock = userShellLock;
    shell.unlock = userShellUnlock;
#endif
    shellInit(&shell, shellBuffer, 512);

#if ASHELL_ASYNCHRONOUS == 1
#if ASHELL_USE_RTOS == 1
    xTaskCreate(AShellTaskProcess, "ShellTask",
                ASHELL_STK_SIZE,
                NULL,
                ASHELL_TASK_PRIO,
                NULL);
#endif
#endif
}

/**
 * @brief 接收函数
 * 
 */
uint16_t Ashell_rx_callback(uint8_t *data, uint16_t len)
{
#if ASHELL_ASYNCHRONOUS == 1
        DataQueueWrite(&shell_queue, data, len);
#else
	uint16_t i = 0;
    for (i = 0; i < len; i++)
    {
        shellHandler(&shell, (char)data[i]);
    }
#endif	
    return 1;
}

#if ASHELL_ASYNCHRONOUS == 1
/**
 * @brief shell处理函数
 * 
 */
void Ashell_task(void)
{
    char data;
    if (shell.read && shell.read(&data, 1) == 1)
    {
        shellHandler(&shell, data);
    }
}

#if ASHELL_ASYNCHRONOUS == 1
#if ASHELL_USE_RTOS == 1
static void AShellTaskProcess(void *pvParameters)
{
    for (;;)
    {
		Ashell_task();
        vTaskDelay(pdMS_TO_TICKS(10));
    }    
}
#endif
#endif

/**
 * @brief shell读数据
 * 
 * @param data 数据
 * @param len 数据长度
 * 
 * @return short 实际读取到
 */
short Ashell_read(uint8_t *data, unsigned short len)
{
    if (data == NULL || len == 0 || shell.read == NULL)
        return 0;
    
    return shell.read((char *)data, len);

}

/**
 * @brief shell写数据
 * 
 * @param data 数据
 * @param len 数据长度
 * 
 * @return short 实际读取到
 */
short Ashell_write(uint8_t *data, unsigned short len)
{
    if (data == NULL || len == 0 || shell.write == NULL)
        return 0;
    
    return shell.write((char *)data, len);
}

/**
 * @brief shell清空输入输出
 * 
 * 
 * @return short <0:失败
 */
short Ashell_flush_read(uint8_t *data, unsigned short len)
{
    if (data == NULL || len == 0 || shell.read == NULL)
        return 0;

    if (shell.flush != NULL)
    {
        shell.flush();
    }
    return shell.read((char *)data, len);
}

#endif
